package com.boat.starter.ruoyi.service;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;

import com.boat.framework.base.exception.CommonErrorCode;
import com.boat.framework.base.exception.ServiceException;
import com.boat.starter.ruoyi.annotation.AdmAuthLogin;
import com.boat.starter.ruoyi.annotation.AdmAuthPerm;
import com.boat.starter.ruoyi.annotation.AdmAuthRole;
import com.boat.starter.ruoyi.annotation.AdmAuthUser;
import com.boat.starter.ruoyi.client.RedisClient;
import com.boat.starter.ruoyi.client.RuoyiClient;
import com.boat.starter.ruoyi.client.response.RmsResponse;
import com.boat.starter.ruoyi.config.props.AdmAuthConsts;
import com.boat.starter.ruoyi.config.props.AuthProperties;
import com.boat.starter.ruoyi.model.LoginUser;
import com.boat.starter.ruoyi.model.dto.SysRole;
import com.boat.starter.ruoyi.util.ServletUtils;

import cn.hutool.core.util.StrUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;

/**
 * Rms鉴权服务
 * 
 * @author 周江
 *
 */
@Slf4j
public class AdmAuthService {

	private AuthProperties authProperties;

	private Set<String> refreshTokenList = new HashSet<>();

	private Set<String> syncTokenList = new HashSet<>();

	@Autowired
	RedisClient redisClient;

	@Autowired
	RuoyiClient ruoyiClient;

	public AdmAuthService(AuthProperties authProperties) {
		this.authProperties = authProperties;
	}

	/**
	 * 用户认证
	 * 
	 * @param token
	 * @param rmsAuths
	 */
	public void auth(String token, Annotation[] annotations) {
		if (!isFormatValidToken(token)) {
			throw new ServiceException(CommonErrorCode.AUTH_USER_NO_LOGIN);
		}

		LoginUser loginUser = getLoginUser(token);
		if (loginUser == null) {
			throw new ServiceException(CommonErrorCode.AUTH_USER_NO_LOGIN);
		}

		for (Annotation annotation : annotations) {
			// 用户登录检查
			if (annotation instanceof AdmAuthLogin) {
				if (loginUser == null) {
					throw new ServiceException(CommonErrorCode.AUTH_USER_NO_LOGIN);
				}
			}

			// 权限项检查
			else if (annotation instanceof AdmAuthPerm) {
				String permItem = ((AdmAuthPerm) annotation).value();
				if (loginUser.getPermissions() == null || loginUser.getPermissions().isEmpty()) {
					throw new ServiceException(CommonErrorCode.AUTH_PERMISSION_DENIED);
				}
				if (loginUser.getPermissions().contains("*:*:*")) {
					continue;
				}
				if (!loginUser.getPermissions().contains(permItem)) {
					throw new ServiceException(CommonErrorCode.AUTH_PERMISSION_DENIED);
				}
			}

			// 角色检查
			else if (annotation instanceof AdmAuthRole) {
				if (null == loginUser.getUser().getRoles()) {
					throw new ServiceException(CommonErrorCode.AUTH_PERMISSION_DENIED);
				}

				List<SysRole> sysRoleList = loginUser.getUser().getRoles();
				List<String> roleKeyList = new ArrayList<>();
				for (SysRole s : sysRoleList) {
					roleKeyList.add(s.getRoleKey());
				}

				String roleName = ((AdmAuthRole) annotation).value();
				if (!roleKeyList.contains(roleName) && !roleKeyList.contains("*:*:*")) {
					throw new ServiceException(CommonErrorCode.AUTH_PERMISSION_DENIED);
				}
			}

			// 用户名检查
			else if (annotation instanceof AdmAuthUser) {
				String userCode = ((AdmAuthUser) annotation).value();
				if (!userCode.equals(loginUser.getUsername())) {
					throw new ServiceException(CommonErrorCode.AUTH_PERMISSION_DENIED);
				}
			}
		}
		
		//通过认证，定时续约token
		addRefreshTokenList(token);
	}

	/**
	 * 获取用户身份信息(免参)
	 *
	 * @return 用户信息
	 */
	public LoginUser getLoginUser() {
		String token = ServletUtils.getToken();

		if (!isFormatValidToken(token)) {
			return null;
		}

		return getLoginUser(token);
	}

	/**
	 * 每分钟执行一次
	 */
	@Scheduled(fixedDelay = 60 * 1000)
	public void refreshTokens() {
		synchronized (refreshTokenList) {
			syncTokenList.addAll(refreshTokenList);
			refreshTokenList.clear();
		}

		if (syncTokenList.isEmpty()) {
			if (log.isDebugEnabled()) {
				log.debug("tokens列表为空，不同步");
			}
		} else {
			log.info("tokens续约开始");
			RmsResponse<Void> rmsResponse = ruoyiClient.refreshTokens(syncTokenList);
			if (rmsResponse.isSuccess()) {
				syncTokenList.clear();
			}
		}
	}

	public void addRefreshTokenList(String token) {
		if (!isFormatValidToken(token)) {
			log.debug("不是合法的token格式:{}", token);
			return;
		}

		synchronized (refreshTokenList) {
			refreshTokenList.add(token);
		}
	}

	public LoginUser getLoginUser(String token) {
		if (!isFormatValidToken(token)) {
			return null;
		}

		try {
			Claims claims = parseToken(token);
			// 解析对应的权限以及用户信息
			String loginUserKey = (String) claims.get(AdmAuthConsts.Token.LOGIN_USER_KEY);
			String tokenKey = getTokenKey(loginUserKey);
			return redisClient.getLoginUser(tokenKey);
		} catch (Exception ex) {
			log.warn("获取当前登录用户信息出错，错误消息：" + ex.getMessage());
			return null;
		}
	}

	/**
	 * 是否格式有效的token值
	 * 
	 * @param token
	 * @return
	 */
	public boolean isFormatValidToken(String token) {
		if (StrUtil.isBlank(token)) {
			return false;
		}
		try {
			parseToken(token);
		} catch (Exception ex) {
			return false;
		}

		return true;
	}

	private Claims parseToken(String token) {
		return Jwts.parser().setSigningKey(authProperties.getRuoyi().getToken().getSecret()).parseClaimsJws(token)
				.getBody();
	}

	private String getTokenKey(String loginUserKey) {
		return AdmAuthConsts.Token.LOGIN_TOKEN_KEY + loginUserKey;
	}

}
